from typing import Container, Optional, Type
from pydantic import BaseConfig, BaseModel, create_model
from sqlalchemy.inspection import inspect
from sqlalchemy.orm.properties import ColumnProperty




# ############################################################################
# ############################# COPY From 开源项目：pydantic-sqlalchemy #############################
# ############ 开源地址： https://github.com/tiangolo/pydantic-sqlalchemy #####################
# ############################################################################

class OrmConfig(BaseConfig):
    orm_mode = True

def sqlalchemy_to_pydantic(
        db_model: Type, *, config: Type = OrmConfig, exclude: Container[str] = []
) -> Type[BaseModel]:
    mapper = inspect(db_model)
    fields = {}
    for attr in mapper.attrs:
        if isinstance(attr, ColumnProperty):
            if attr.columns:
                name = attr.key
                if name in exclude:
                    continue
                column = attr.columns[0]
                python_type: Optional[type] = None
                if hasattr(column.type, "impl"):
                    if hasattr(column.type.impl, "python_type"):
                        python_type = column.type.impl.python_type
                elif hasattr(column.type, "python_type"):
                    python_type = column.type.python_type
                assert python_type, f"Could not infer python_type for {column}"
                default = None
                if column.default is None and not column.nullable:
                    default = ...
                fields[name] = (python_type, default)
    pydantic_model = create_model(db_model.__name__, __config__=config, **fields)
    return pydantic_model

# from typing import List
#
# from pydantic_sqlalchemy import sqlalchemy_to_pydantic
# from sqlalchemy import Column, ForeignKey, Integer, String, create_engine
# from sqlalchemy.ext.declarative import declarative_base
# from sqlalchemy.orm import Session, relationship, sessionmaker
#
# Base = declarative_base()
#
# engine = create_engine("sqlite://", echo=True)
#
#
# class User(Base):
#     __tablename__ = "users"
#
#     id = Column(Integer, primary_key=True)
#     name = Column(String)
#     fullname = Column(String)
#     nickname = Column(String)
#
#     addresses = relationship(
#         "Address", back_populates="user", cascade="all, delete, delete-orphan"
#     )
#
#
# class Address(Base):
#     __tablename__ = "addresses"
#     id = Column(Integer, primary_key=True)
#     email_address = Column(String, nullable=False)
#     user_id = Column(Integer, ForeignKey("users.id"))
#
#     user = relationship("User", back_populates="addresses")
#
#
# PydanticUser = sqlalchemy_to_pydantic(User)
# PydanticAddress = sqlalchemy_to_pydantic(Address)
#
#
# class PydanticUserWithAddresses(PydanticUser):
#     addresses: List[PydanticAddress] = []
